<template>
	<div id="bank-container">

		<div id="bank-header">
			<h1>银行家算法</h1>
		</div>

		<div id="bank-content">
			<div class="bank-content-left">
				<label class="bank-item">进程个数：
					<input class="bank-input" type="number" min="0" max="10" v-model="processNum"
						placeholder="输入进程个数[0,10]">
				</label><br>
				<label class="bank-item">资源种类数：
					<input class="bank-input" type="number" min="0" max="10" v-model="resourcesNum"
						placeholder="输入资源种类数[0,10]">
				</label><br>

				<table class="bank-tb">
					<caption class="bank-tb-title">资源总数量</caption>
					<tr>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
					</tr>
					<tr>
						<td v-for="i in resourcesNum" style="text-align: center;border: 1px solid black;"><input
								type="number" min="0" max="999" placeholder="[0,999]" v-model="resources[i - 1]"></td>
					</tr>
				</table>

				<table class="bank-tb">
					<caption class="bank-tb-title">进程对资源最大需求量</caption>
					<tr>
						<th style="white-space: nowrap;border: 1px solid black;">进程/资源</th>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
					</tr>
					<tr v-for="i in processNum">
						<td style="text-align: center;border: 1px solid black;"><span>进程{{ i }}</span></td>
						<td v-for="j in resourcesNum" style="text-align: center;border: 1px solid black;"><input
								type="number" min="0" max="999" placeholder="[0,999]" v-model="max[i - 1][j - 1]"></td>
					</tr>
				</table>

				<table class="bank-tb">
					<caption class="bank-tb-title">进程已占有资源数量</caption>
					<tr>
						<th style="white-space: nowrap;border: 1px solid black;">进程/资源</th>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
					</tr>
					<tr v-for="i in processNum">
						<td style="text-align: center;border: 1px solid black;"><span>进程{{ i }}</span></td>
						<td v-for="j in resourcesNum" style="text-align: center;border: 1px solid black;"><input
								type="number" min="0" max="999" placeholder="[0,999]"
								v-model="allocation[i - 1][j - 1]"></td>
					</tr>
				</table>

				<table class="bank-tb">
					<caption class="bank-tb-title">系统当前可用资源数量</caption>
					<tr>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
					</tr>
					<tr>
						<td v-for="i in resourcesNum" style="text-align: center;border: 1px solid black;">
							<span>
								{{ calcAvailable[i - 1] ? calcAvailable[i - 1] : 0 }}
							</span>
						</td>
					</tr>
				</table>

				<table class="bank-tb">
					<caption class="bank-tb-title">进程还需资源数量</caption>
					<tr>
						<th style="white-space: nowrap;border: 1px solid black;">进程/资源</th>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
					</tr>
					<tr v-for="i in processNum">
						<td style="text-align: center;border: 1px solid black;"><span>进程{{ i }}</span></td>
						<td v-for="j in resourcesNum" style="text-align: center;border: 1px solid black;">
							<span>
								{{ calcNeed[i - 1][j - 1] ? calcNeed[i - 1][j - 1] : 0 }}
							</span>
						</td>
					</tr>
				</table>
			</div>

			<div class="bank-content-right">
				<table class="bank-tb">
					<caption class="bank-tb-title">进程申请资源数量</caption>
					<tr>
						<th style="white-space: nowrap;border: 1px solid black;">进程/资源</th>
						<th v-for="i in resourcesNum" style="border: 1px solid black;">资源{{ resourcesName[i - 1] }}</th>
						<th style="white-space: nowrap;text-align: center;border: 1px solid black;">操作</th>
					</tr>
					<tr>
						<td style="text-align: center;border: 1px solid black;">
							<select name="requestProcess" id="requestProcess" v-model="pr">
								<option v-for="i in processNum" :value="i"
									style="text-align: center;border: 1px solid black;">进程{{ i }}</option>
							</select>
						</td>
						<td v-for="i in resourcesNum" style="text-align: center;border: 1px solid black;"><input
								type="number" min="0" max="999" placeholder="[0,999]" v-model="request[i - 1]"></td>
						<td style="white-space: nowrap;text-align: center;border: 1px solid black;"><button
								@click="reset">重置</button></td>
					</tr>
				</table>

				<div class="bank-result">
					<span style="font-weight: bolder;">安全性检查结果：</span>
					<span :style="{ color: fontColor }">{{ result }}</span>
				</div>

				<table class="bank-tb" v-show="isSafe">
					<caption class="bank-tb-title">资源分配情况分析</caption>
					<tr>
						<th rowspan="2" style="white-space: nowrap;border: 1px solid black;">进程/资源情况</th>
						<th style="border: 1px solid black;">Work</th>
						<th style="border: 1px solid black;">Need</th>
						<th style="border: 1px solid black;">Allocation</th>
						<th style="border: 1px solid black;">Work+Allocation</th>
						<th rowspan="2" style="border: 1px solid black;">Finish</th>
					</tr>
					<tr>
						<th style="white-space: nowrap;border: 1px solid black;">{{ title }}</th>
						<th style="white-space: nowrap;border: 1px solid black;">{{ title }}</th>
						<th style="white-space: nowrap;border: 1px solid black;">{{ title }}</th>
						<th style="white-space: nowrap;border: 1px solid black;">{{ title }}</th>
					</tr>
					<tr v-for="i in processNum">
						<td style="text-align: center;border: 1px solid black;">进程{{ safequeue[i - 1] + 1 }}</td>
						<td style="text-align: center;border: 1px solid black;">{{ workResult(i - 1) }}</td>
						<td style="text-align: center;border: 1px solid black;">{{ needResult(i - 1) }}</td>
						<td style="text-align: center;border: 1px solid black;">{{ allocationResult(i - 1) }}</td>
						<td style="text-align: center;border: 1px solid black;">{{ workAndAllocResult(i - 1) }}</td>
						<td style="text-align: center;border: 1px solid black;">{{ finish[i - 1] }}</td>
					</tr>
				</table>
			</div>
		</div>
	</div>
</template>

<script>
export default {
	name: "Bank",
	components: {},
	data() {
		return {
			resourcesName: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
			fontWarn: '#ff0',
			fontError: '#f00',
			fontSafe: '#0f0',
			fontColor: '#0f0',
			isSafe: false,
			processNum: 0,//进程个数
			resourcesNum: 0,//资源个数
			resources: null,// 资源总数
			max: null,//进程对资源最大需求量
			allocation: null,//进程已占有资源数量
			available: null,//系统当前可用资源数量
			need: null,//进程还需资源数量
			work: null,//工作向量
			finish: null,
			request: null,//进程申请资源数量
			safequeue: null,     // 进程执行顺序
			pr: null,//申请资源的进程
			rest: null,
			ava: null,
			alloc: null,
			nd: null,
			lock1:false,//简单模拟下同步锁
			lock2:false,//简单模拟下同步锁
			lock3:false,//简单模拟下同步锁
			lock4:false,//简单模拟下同步锁
		}
	},
	computed: {
		calcAvailable() {//系统当前可用资源数量
			if(this.lock1){
				return this.available;
			}
			this.lock1=true;
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			for (let i = 0; i < this.resourcesNum; i++) {
				this.available[i] = this.resources[i];
			}

			for (let i = 0; i < this.processNum; i++) {
				for (let j = 0; j < this.resourcesNum; j++) {
					this.available[j] -= this.allocation[i][j];
				}
			}
			this.lock1=false;
			return this.available;
		},
		calcNeed() {//进程还需资源数量
			if(this.lock2){
				return this.need;
			}
			this.lock2=true;
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			for (let i = 0; i < this.processNum; i++) {
				for (let j = 0; j < this.resourcesNum; j++) {
					this.need[i][j] = this.max[i][j];
				}
			}

			for (let i = 0; i < this.processNum; i++) {
				for (let j = 0; j < this.resourcesNum; j++) {
					this.need[i][j] -= this.allocation[i][j];
				}
			}
			this.lock2=false;
			return this.need;
		},
		title() {
			if(this.lock3){
				return ' ';
			}
			this.lock3=true;
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			let title = ' ';
			for (let index = 0; index < this.resourcesNum; index++) {
				title += this.resourcesName[index] + ' ';
			}
			this.lock3=true;
			return title;
		},
		result() {
			if(this.lock4){
				return ' ';
			}
			this.lock4=true;
			this.isSafe = false;

			if (!this.processNum || !this.resourcesNum) {
				this.fontColor = this.fontWarn;
				this.lock4=false;
				return "请设置初始化参数";
			}
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}

			//检查资源总数是否合法
			for (let index = 0; index < this.resourcesNum; index++) {
				this.ava[index] = this.available[index];
				if (this.resources[index] < 0 || this.resources[index] > 999) {
					this.fontColor = this.fontWarn;
					this.lock4=false;
					return "请检查资源总数是否合法";
				}
			}

			//检查进程对资源最大需求量是否合法
			for (let i = 0; i < this.processNum; i++) {
				for (let j = 0; j < this.resourcesNum; j++) {
					if (this.max[i][j] < 0 || this.max[i][j] > 999) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "请检查进程对资源最大需求量是否合法";
					}
					if (this.max[i][j] > this.resources[j]) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "进程" + (i + 1) + "对资源" + this.resourcesName[j] + "的需求超过该资源总数";
					}
				}
			}

			//检查进程已占有资源数量是否合法
			for (let i = 0; i < this.processNum; i++) {
				for (let j = 0; j < this.resourcesNum; j++) {
					if (this.allocation[i][j] < 0 || this.allocation[i][j] > 999) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "请检查进程已占有资源数量是否合法";
					}
					if (this.allocation[i][j] > this.max[i][j]) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "进程" + (i + 1) + "得到的资源" + this.resourcesName[j] + "数量超过申明的最大值";
					}
					if (this.allocation[i][j] > this.resources[j]) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "进程" + (i + 1) + "得到的资源" + this.resourcesName[j] + "数量超过该资源总数";
					}

					this.alloc[i][j] = this.allocation[i][j];
					this.nd[i][j] = this.need[i][j];
				}

			}

			if (this.pr && this.pr <= this.processNum) {//分配申请的资源
				for (let i = 0; i < this.resourcesNum; i++) {
					this.ava[i] -= this.request[i];
					this.alloc[this.pr - 1][i] += this.request[i];
					this.nd[this.pr - 1][i] -= this.request[i];
					if (this.alloc[this.pr - 1][i] > this.max[this.pr - 1][i]) {
						this.fontColor = this.fontWarn;
						this.lock4=false;
						return "进程" + this.pr + "得到的资源" + this.resourcesName[i] + "数量超过申明的最大值";
					}
				}
			}

			for (let i = 0; i < this.resourcesNum; i++) {
				this.work[i] = this.ava[i];
			}

			for (let i = 0; i < this.processNum; i++) {
				this.finish[i] = false;
			}

			let flag = 1;
			let bFlag = 0;

			for (let index = 0; index < 10; index++) {
				this.rest[index] = 0;
			}
			let k = 0;
			for (let i = 0; i < this.processNum; i++) { // 全部进程进入集合rest
				this.rest[i] = i;
			}

			while (true) {

				bFlag = 0;
				for (let i = 0; i < this.processNum; i++) {
					if (this.rest[i] == -1) {
						continue;
					}
					for (let j = 0; j < this.resourcesNum; j++) {
						if (this.nd[i][j] > this.work[j]) {
							flag = 0;
							bFlag++;
							this.finish[i] = false;
							break;
						}
					}
					if (flag) {
						for (let j = 0; j < this.resourcesNum; j++) {

							this.work[j] += this.alloc[i][j];
						}
						this.safequeue[k++] = i;
						this.rest[i] = -1;
						this.finish[i] = true;
					} else {
						flag = 1;
						continue;
					}
				}
				if (bFlag == this.processNum) {
					break;
				}
				if (k == this.processNum) {
					break;
				}
			}

			for (let i = 0; i < this.processNum; i++) {
				if (this.rest[i] != -1) {
					this.fontColor = this.fontError
					this.lock4=false;
					return "系统不安全...";
				}
			}
			this.fontColor = this.fontSafe;
			this.isSafe = true;
			let r = "系统安全，存在安全序列{";
			for (let i = 0; i < this.processNum; i++) {
				r += (this.safequeue[i] + 1);
				if (i < this.processNum - 1) {
					r += ",";
				}
			}
			r += "}";
			this.lock4=false;
			return r;
		},
	},

	methods: {
		reset() {
			this.pr = null;
			for (let index = 0; index < 10; index++) {
				this.request[index] = 0;
			}

		},
		workResult(i) {
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			let n = " ";
			for (let j = 0; j < this.resourcesNum; j++) {
				let r = this.work[j];
				for (let index = this.processNum - 1; index >= i; index--) {
					r -= this.alloc[index][j];
				}
				n += r + " ";
			}
			return n
		},
		needResult(i) {
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			let n = " ";
			for (let j = 0; j < this.resourcesNum; j++) {
				n += this.max[i][j] - this.alloc[i][j] + " ";
			}
			return n
		},

		allocationResult(i) {
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			let n = " ";
			for (let j = 0; j < this.resourcesNum; j++) {
				n += this.alloc[i][j] + " ";
			}
			return n
		},
		workAndAllocResult(i) {
			if (this.processNum < 0) {
				this.processNum = 0;
			}
			if (this.resourcesNum < 0) {
				this.resourcesNum = 0;
			}
			if (this.processNum > 10) {
				this.processNum = 10;
			}
			if (this.resourcesNum > 10) {
				this.resourcesNum = 10;
			}
			let n = " ";
			for (let j = 0; j < this.resourcesNum; j++) {
				let r = this.work[j];
				for (let index = this.processNum - 1; index > i; index--) {
					r -= this.alloc[index][j];
				}
				n += r + " ";
			}
			return n
		},

	},
	created() {
		this.resources = new Array(10);
		this.max = new Array(10);
		this.allocation = new Array(10);
		this.work = new Array(10);
		this.alloc = new Array(10);
		this.nd = new Array(10);
		this.need = new Array(10);
		this.request = new Array(10);
		this.safequeue = new Array(10);
		this.finish = new Array(10);
		this.ava = new Array(10);
		this.available = new Array(10);
		this.rest = new Array(10);
		for (let index = 0; index < 10; index++) {
			this.resources[index] = 0;
			this.request[index] = 0;
			this.rest[index] = 0;
			this.safequeue[index] = 0;
			this.finish[index] = false;
			this.ava[index] = 0;
			this.available[index] = 0;
			this.max[index] = new Array(10);
			this.allocation[index] = new Array(10);
			this.work[index] = new Array(10);
			this.alloc[index] = new Array(10);
			this.nd[index] = new Array(10);
			this.need[index] = new Array(10);
			for (let j = 0; j < 10; j++) {
				this.max[index][j] = 0;
				this.allocation[index][j] = 0;
				this.work[index][j] = 0;
				this.alloc[index][j] = 0;
				this.nd[index][j] = 0;
				this.need[index][j] = 0;
			}
		}
	},
	mounted() {
	},
	beforeUnmount() {
	},
}
</script>

<style scoped>
#bank-container {
	width: 100vw;
	height: 100vh;
	display: flex;
	background-color: rgb(175, 186, 196);
	position: relative;
	justify-content: center;
}

#bank-header {
	position: absolute;
	height: 100px;
}

#bank-content {
	position: absolute;
	top: 100px;
	width: 100%;
	height: 80%;
}

.bank-content-left {
	position: absolute;
	padding: 10px;
	left: 50px;
	width: 45%;
	height: 100%;
	background-color: rgb(178, 165, 183);
	overflow-y: auto;
}

.bank-content-right {
	position: absolute;
	padding: 10px;
	right: 50px;
	width: 45%;
	height: 100%;
	background-color: rgb(164, 161, 154);
	overflow-y: auto;
}

.bank-item {
	display: inline-block;
	width: 300px;
}

.bank-input {
	float: right;
	width: 150px;
}

.bank-tb {
	position: relative;
	border: 2px solid black;
	margin: 50px;
	width: 80%;
}

.bank-tb-title {
	font-weight: bolder;
	font-size: large;
	margin: 10px;
}

.bank-result {
	margin: 50px;
}
</style>